#include "platform/opengl/opengl_framebuffer.hpp"

namespace Xen {

OpenGLFramebuffer::OpenGLFramebuffer(const FrameBufferInfo &info):info_(info) {
    GLCall(glGenFramebuffers(1, &fbo_));
}

OpenGLFramebuffer::~OpenGLFramebuffer() {
    GLCall(glDeleteFramebuffers(1, &fbo_));
}

void OpenGLFramebuffer::NoColorAttachment() {
    Bind();
    GLCall(glDrawBuffer(GL_NONE));
    GLCall(glReadBuffer(GL_NONE));
    Unbind();
}

void OpenGLFramebuffer::Bind() const {
    switch (info_.rw) {
        case FrameBufferRW::READ:
            GLCall(glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_));
            break;
        case FrameBufferRW::WRITE:
            GLCall(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_));
            break;
        case FrameBufferRW::READ_WRITE:
            GLCall(glBindFramebuffer(GL_FRAMEBUFFER, fbo_));
            break;
    }
}

void OpenGLFramebuffer::Unbind() const {
    GLCall(glBindFramebuffer(GL_FRAMEBUFFER, 0));
}

bool OpenGLFramebuffer::IsComplete() const {
    Bind();
    bool result = (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    Unbind();
    return result;
}

void OpenGLFramebuffer::AddColorAttachment(const Ref<Texture2D> &color_attachment) {
    Bind();
    GLCall(glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0 + color_attachments_.size(),
            GL_TEXTURE_2D,
            dynamic_cast<OpenGLTexture2DBase*>(color_attachment.get())->tex_,
            0
    ));
    color_attachments_.push_back(color_attachment);
    Unbind();
}

void OpenGLFramebuffer::AddDepthAttachment(const Ref<Texture2D> &depth_attachment) {
    Bind();
    GLCall(glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            GL_DEPTH_ATTACHMENT,
            GL_TEXTURE_2D,
            dynamic_cast<OpenGLTexture2DBase*>(depth_attachment.get())->tex_,
            0
    ));
    depth_attachment_ = depth_attachment;
    Unbind();

}

void OpenGLFramebuffer::AddDepthStencilAttachment(const Ref<Texture2D> &depth_stencil_attachment) {
    Bind();
    GLCall(glFramebufferTexture2D(
            GL_FRAMEBUFFER,
            GL_DEPTH_STENCIL_ATTACHMENT,
            GL_TEXTURE_2D,
            dynamic_cast<OpenGLTexture2DBase*>(depth_stencil_attachment.get())->tex_,
            0
    ));
    depth_stencil_attachment_ = depth_stencil_attachment;
    Unbind();
}

}
